package com.ys.utils;

import org.apache.commons.lang3.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.management.ManagementFactory;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 时间工具类
 *
 * @author anxin.sys
 */
public class DateUtils extends org.apache.commons.lang3.time.DateUtils {

  private static Logger logger = LoggerFactory.getLogger("sys-error");
  public static final String YYYY = "yyyy";

  public static final String YYYY_MM = "yyyy-MM";

  public static final String YYYY_MM_DD_C = "yyyy年MM月dd";

  public static final String YYYY_MM_DD = "yyyy-MM-dd";

  public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";

  public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";

  public static final String HH_MM_SS = "HH:mm:ss";

  public static final String HH_MM = "HH:mm";

  private static final String[] parsePatterns = {
      "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
      "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
      "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};

  /**
   * 获取当前Date型日期
   *
   * @return Date() 当前日期
   */
  public static Date getNowDate() {
    return new Date();
  }

  /**
   * 获取当前日期, 默认格式为yyyy-MM-dd
   *
   * @return String
   */
  public static String getDate() {
    return dateTimeNow(YYYY_MM_DD);
  }

  public static final String getTime() {
    return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
  }

  public static final String dateTimeNow() {
    return dateTimeNow(YYYYMMDDHHMMSS);
  }

  public static final String dateTimeNow(final String format) {
    return parseDateToStr(format, new Date());
  }

  public static final String dateTime(final Date date) {
    return parseDateToStr(YYYY_MM_DD, date);
  }

  public static final String parseDateToStr(final String format, final Date date) {
    return new SimpleDateFormat(format).format(date);
  }

  /**
   * 格式化日期
   *
   * @param format
   * @param date
   * @return
   */
  public static String format(String format, Date date) {
    if (date != null) {
      if (StringUtils.isNotBlank(format)) {
        return parseDateToStr(format, date);
      }

      return parseDateToStr(YYYY_MM_DD, date);
    }
    return "";
  }

  public static String format(Date date) {
    if (date != null) {
      return parseDateToStr(YYYY_MM_DD, date);
    }
    return "";
  }

  public static final Date dateTime(final String format, final String ts) {
    try {
      return new SimpleDateFormat(format).parse(ts);
    } catch (ParseException e) {
      throw new RuntimeException(e);
    }
  }

  /**
   * 日期路径 即年/月/日 如2018/08/08
   */
  public static final String datePath() {
    Date now = new Date();
    return DateFormatUtils.format(now, "yyyy/MM/dd");
  }

  /**
   * 日期路径 即年/月/日 如20180808
   */
  public static final String dateTime() {
    Date now = new Date();
    return DateFormatUtils.format(now, "yyyyMMdd");
  }

  /**
   * 日期型字符串转化为日期 格式
   */
  public static Date parseDate(Object str) {
    if (str == null) {
      return null;
    }
    try {
      return parseDate(str.toString(), parsePatterns);
    } catch (ParseException e) {
      return null;
    }
  }

  /**
   * 获取服务器启动时间
   */
  public static Date getServerStartDate() {
    long time = ManagementFactory.getRuntimeMXBean().getStartTime();
    return new Date(time);
  }

  /**
   * 计算两个时间差
   */
  public static String getDatePoor(Date endDate, Date nowDate) {
    // 获得两个时间的毫秒时间差异
    long diff = endDate.getTime() - nowDate.getTime();
    return DateUtils.timeStampToDate(diff / 1000);
  }

  /**
   * 返回当前日期的最大时分秒 23：59：59
   *
   * @param date
   * @return
   */
  public static Date getMaxTime(Date date) {
    Calendar cal1 = Calendar.getInstance();
    cal1.setTime(date);
    // 将时分秒,毫秒域清零
    cal1.set(Calendar.HOUR_OF_DAY, 23);
    cal1.set(Calendar.MINUTE, 59);
    cal1.set(Calendar.SECOND, 59);
    return cal1.getTime();
  }

  /**
   * 获取俩个日期相差的天数
   *
   * @param endDate 开始日期
   * @param nowDate 结束日期
   * @return
   */
  public static Long getDateDayPoor(Date nowDate, Date endDate) {
    Calendar cal1 = Calendar.getInstance();
    cal1.setTime(nowDate);
    cal1.set(Calendar.HOUR_OF_DAY, 0);
    cal1.set(Calendar.MINUTE, 0);
    cal1.set(Calendar.SECOND, 0);
    cal1.set(Calendar.MILLISECOND, 0);

    Calendar cal2 = Calendar.getInstance();
    cal2.setTime(endDate);
    cal2.set(Calendar.HOUR_OF_DAY, 0);
    cal2.set(Calendar.MINUTE, 0);
    cal2.set(Calendar.SECOND, 0);
    cal2.set(Calendar.MILLISECOND, 0);
    endDate = cal2.getTime();

    return (endDate.getTime() - nowDate.getTime()) / (60 * 60 * 24 * 1000);
  }

  /**
   * 获取俩个日期相差的月份
   *
   * @param endDate 开始日期
   * @param nowDate 结束日期
   * @return
   */
  public static Integer getDateMonthPoor(Date nowDate, Date endDate) {
    Calendar cal1 = Calendar.getInstance();
    cal1.setTime(nowDate);
    cal1.set(Calendar.HOUR_OF_DAY, 0);
    cal1.set(Calendar.MINUTE, 0);
    cal1.set(Calendar.SECOND, 0);
    cal1.set(Calendar.MILLISECOND, 0);

    Calendar cal2 = Calendar.getInstance();
    cal2.setTime(endDate);
    cal2.set(Calendar.HOUR_OF_DAY, 0);
    cal2.set(Calendar.MINUTE, 0);
    cal2.set(Calendar.SECOND, 0);
    cal2.set(Calendar.MILLISECOND, 0);

    int  year = cal2.get(Calendar.YEAR) - cal1.get(Calendar.YEAR);
    return cal2.get(Calendar.MONTH)+year*12 - cal1.get(Calendar.MONTH);
  }


  /**
   * 时间戳转时间
   *
   * @param timeStamp
   * @return
   */
  public static String timeStampToDate(Long timeStamp) {
    long nd = 24 * 60 * 60L;
    long nh = 60 * 60L;
    long nm = 60L;
    // long ns = 1000;
    // 计算差多少天
    long day = timeStamp / nd;
    // 计算差多少小时
    long hour = timeStamp % nd / nh;
    // 计算差多少分钟
    long min = timeStamp % nd % nh / nm;
    // 计算差多少秒//输出结果
    // long sec = diff % nd % nh % nm / ns;
    StringBuffer resString = new StringBuffer();
    if (day > 0) {
      resString.append(day + "天");
    }
    if (hour > 0) {
      resString.append(hour + "小时");
    }
    resString.append(min + "分钟");
    return resString.toString();
  }

  public static String getYear() {
    return formatDate(new Date(), "yyyy");
  }

  public static String getYear(Date date) {
    return formatDate(date, "yyyy");
  }

  public static String getMonth() {
    return formatDate(new Date(), "MM");
  }

  public static String getMonth(Date date) {
    return formatDate(date, "MM");
  }

  public static String getDay() {
    return formatDate(new Date(), "dd");
  }

  public static String getDay(Date date) {
    return formatDate(date, "dd");
  }

  public static String getWeek() {
    return formatDate(new Date(), "E");
  }

  public static String formatDate(Date date, Object... pattern) {
    String formatDate = null;
    if (pattern != null && pattern.length > 0) {
      formatDate = DateFormatUtils.format(date, pattern[0].toString());
    } else {
      formatDate = DateFormatUtils.format(date, "yyyy-MM-dd");
    }

    return formatDate;
  }

  /**
   * 获取日期
   *
   * @param year  年
   * @param month 月
   * @param day   日
   * @return 返回日期
   */
  public static Date getDate(int year, int month, int day) {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    Date date = null;
    try {
      date = sdf.parse(year + "-" + month + "-" + day);
      if (Integer.parseInt(DateUtils.formatDate(date, "MM")) > month) {
        Calendar rightNow = Calendar.getInstance();
        rightNow.setTime(date);
        rightNow.add(Calendar.MONTH, -1);
        rightNow.set(Calendar.DAY_OF_MONTH, rightNow.getActualMaximum(Calendar.DAY_OF_MONTH));
        date = rightNow.getTime();
      }
    } catch (ParseException e) {
      logger.error("DateUtils--getDate 获取日期异常", e);
    }
    return date;
  }


  /**
   * 获取指定日期的季度
   *
   * @param date 指定日期
   * @return 指定日期对应的季度
   */
  public static String getQuarter(Date date) {
    Calendar c = Calendar.getInstance();
    c.setTime(date);
    int month = c.get(c.MONTH) + 1;
    int quarter = 0;
    if (month >= 1 && month <= 3) {
      quarter = 1;
    } else if (month >= 4 && month <= 6) {
      quarter = 2;
    } else if (month >= 7 && month <= 9) {
      quarter = 3;
    } else {
      quarter = 4;
    }
    return quarter + "";
  }

  /**
   * 获取历史年份(不包含当前年)
   *
   * @param num 需要获取历史几年的数据？
   * @return 年份集合
   */
  public static List<Integer> getHistoryYear(Integer num) {
    List<Integer> historyYearList = new ArrayList<>();
    Calendar cal = Calendar.getInstance();
    // 当前年
    int year = cal.get(Calendar.YEAR);
    for (int i = num; i > 0; i--) {
      historyYearList.add(year - i);
    }
    return historyYearList;
  }

  /**
   * 拼接日期
   *
   * @param date      日期
   * @param startTime 开始时间
   * @param endTime   结束时间
   * @return 拼接后的日期
   */
  public static String joinTime(Date date, String startTime, String endTime) {
    String dateFormat = DateUtils.format(date);
    try {
      String startTimeFormat = new SimpleDateFormat(HH_MM)
          .format(new SimpleDateFormat(HH_MM_SS).parse(startTime));
      String endTimeFormat = new SimpleDateFormat(HH_MM)
          .format(new SimpleDateFormat(HH_MM_SS).parse(endTime));
      return dateFormat + " " + startTimeFormat + "-" + endTimeFormat;
    } catch (ParseException e) {
      logger.error("DateUtils--joinTime 拼接日期异常", e);
    }
    return "";
  }

  /**
   * 两日期去头去尾相差天和月
   *
   * @param startDate 开始时间
   * @param endDate   结束时间
   * @return 头尾天数+间隔月数
   */
  public static Map<String, Double> getDaysMonths(Date startDate, Date endDate) {
    Map<String, Double> map = new HashMap<>();
    map.put("head", 0D);
    map.put("months", 0D);
    map.put("tail", 0D);
    if (startDate == null || endDate == null || startDate.getTime() > endDate.getTime()) {
      return map;
    }
    Calendar calendarStart = Calendar.getInstance();
    calendarStart.setTime(startDate);
    //开始时间所在天
    Integer startDateDate = calendarStart.get(Calendar.DATE);
    calendarStart.set(Calendar.DAY_OF_MONTH, 1);
    calendarStart.set(Calendar.DATE, calendarStart.getActualMaximum(Calendar.DATE));
    //开始时间所在月最后一天
    Date startDateMonthLastDay = calendarStart.getTime();
    //开始时间和结束时间在同一个月
    if (startDateMonthLastDay.getTime() >= endDate.getTime()) {
      //开始时间和结束时间为整月
      if (startDateDate == 1 && startDateMonthLastDay.getTime() == endDate.getTime()) {
        map.put("months", 1D);
      } else {
        map.put("head", getDateDayPoor(startDate, endDate) + 1D);
      }
      return map;
    }
    Integer months = getMonthCount(startDate, endDate);
    if (startDateDate == 1) {
      months++;
    } else {
      map.put("head", getDateDayPoor(startDate, startDateMonthLastDay) + 1D);
    }
    Calendar calendarEnd = Calendar.getInstance();
    calendarEnd.setTime(endDate);
    if (calendarEnd.get(Calendar.DATE) == calendarEnd.getActualMaximum(Calendar.DATE)) {
      months++;
    } else {
      map.put("tail", (double) calendarEnd.get(Calendar.DATE));
    }
    map.put("months", (double) months);
    return map;
  }

  /**
   * 获取两日期相差月
   *
   * @param startDate 开始时间
   * @param endDate   结束时间
   * @return 相差月数
   */
  public static Integer getMonthCount(Date startDate, Date endDate) {
    Calendar calendarStart = Calendar.getInstance();
    calendarStart.setTime(startDate);
    calendarStart.set(Calendar.DATE, 1);
    Calendar calendarEnd = Calendar.getInstance();
    calendarEnd.setTime(endDate);
    calendarEnd.set(Calendar.DATE, 1);
    calendarStart.set(Calendar.MONTH, calendarStart.get(Calendar.MONTH) + 1);
    Integer months = 0;
    for (Date date = calendarStart.getTime(); date.getTime() < calendarEnd.getTime().getTime(); ) {
      calendarStart.setTime(date);
      calendarStart.set(Calendar.MONTH, calendarStart.get(Calendar.MONTH) + 1);
      date = calendarStart.getTime();
      months++;
    }
    return months;
  }

  /**
   * 获取上季度末时间
   *
   * @param date 时间
   * @return 上季度末
   */
  public static Date getLastQuarterEnd(Date date) {
    if (date == null) {
      date = getNowDate();
    }
    Calendar calendar = Calendar.getInstance();
    calendar.setTime(date);
    calendar.set(Calendar.MONTH, (calendar.get(Calendar.MONTH) / 3 - 1) * 3 + 2);
    calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
    return getMaxTime(calendar.getTime());
  }

  /**
   * 获取本季度末时间
   *
   * @param date 时间
   * @return 本季度末
   */
  public static Date getThisQuarterEnd(Date date) {
    if (date == null) {
      date = getNowDate();
    }
    Calendar calendar = Calendar.getInstance();
    calendar.setTime(date);
    calendar.set(Calendar.MONTH, (calendar.get(Calendar.MONTH) / 3) * 3 + 2);
    calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
    return getMaxTime(calendar.getTime());
  }

  /**
   * 获取最小值
   *
   * @param date1
   * @param date2
   * @return 最小日期
   */
  public static Date getMinDate(Date date1, Date date2) {
    return date1.getTime() < date2.getTime() ? date1 : date2;
  }

  /**
   * 获取最大值
   *
   * @param date1
   * @param date2
   * @return 最大日期
   */
  public static Date getMaxDate(Date date1, Date date2) {
    return date1.getTime() > date2.getTime() ? date1 : date2;
  }

}

